import React, {FC, useEffect, useRef, useState} from 'react';
import {Summary} from "../entity/Summary";
import {Group, Layer, Line, Rect, Stage, Text} from "react-konva";
import Konva from "konva";
import Edge, {ArrowEnum, EdgeProps} from "./Edge";
import {XYCoord} from "react-dnd";
import {useMount, useScroll} from "ahooks";
import useGlobalStore from "../store/UseGlobalStore";


const itemHeight = 15;


export type ItemGraph = {
  name: string;
  x: number;
  y: number;
  width: number;
  height: number;
}

let scale = 1;

export interface DrawScrollProps {
  width: number;
  height: number;
  summaries: Summary[];
  summaryIndex: number;
  onClick: (index: number) => void;
  pos1: XYCoord;
}

const DrawScroll: FC<DrawScrollProps> = (props) => {
  const {width, pos1, height, summaries, summaryIndex, onClick} = props;
  const [itemSpacing, setItemSpacing] = useState(100);
  const [edgeFontSize, setEdgeFontSize] = useState(12);
  const {downloadStream, pcapResult} = useGlobalStore()
  const [gScale, setGScale] = useState(1);
  let pRef = useRef<HTMLDivElement | null>(null);
  const scroll = useScroll(pRef);
  const stageRef = useRef<Konva.Stage | null>(null);
  const [itemGraphs, setItemGraphs] = useState<ItemGraph[]>([]);
  const [lineGraphs, setLineGraphs] = useState<ItemGraph[][]>([]);
  const [edges, setEdges] = useState<EdgeProps[]>([]);
  const [layer2Y, setLayer2Y] = useState(0);
  const [layerSize, setLayerSize] = useState<{ width: number, height: number }>({width: 0, height: 0});
  useEffect(() => {
    if (!pcapResult) return
    if (edges.length > 0) {
      edges.forEach(x => x.isHigh = false);
      let selectEdge = edges[summaryIndex];
      let coor: { x: number; y: number };
      if (selectEdge.arrow === ArrowEnum.right) {
        coor = {x: selectEdge.startNode.x, y: selectEdge.startNode.y};
      } else {
        coor = {x: selectEdge.endNode.x, y: selectEdge.endNode.y};
      }
      if (pRef.current) {
        pRef.current?.scrollTo({left: (coor.x - 50) * gScale, top: (coor.y - height / 2) * gScale});
      }
      selectEdge.isHigh = true;
    }
  }, [summaryIndex, edges]);
  useEffect(() => {
    if (downloadStream) {
      onClick(0)
      // 等一会，index 跳到0 在下载
      setTimeout(() => {
        let dataURI = stageRef.current?.toDataURL();
        if (dataURI) {
          const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; // mime类型
          const byteString = atob(dataURI.split(',')[1]); //base64 解码
          const arrayBuffer = new ArrayBuffer(byteString.length); //创建缓冲数组
          const intArray = new Uint8Array(arrayBuffer); //创建视图

          for (let i = 0; i < byteString.length; i++) {
            intArray[i] = byteString.charCodeAt(i);
          }
          const fileURL = window.URL.createObjectURL(new Blob([intArray], {type: mimeString}));
          const fileLink = document.createElement('a');

          const lala : any[] = [
            {id:1,name:'lala'},
            {id:2,name:'lala'},
            {id:3,name:'lala'},
            {id:4,name:'lala'},
            {id:5,name:'lala'},
            {id:6,name:'lala'},
            {id:7,name:'lala'},
            {id:8,name:'lala'},
            {id:9,name:'lala'},
            {id:10,name:'lala'},
            {id:11,name:'lala'},
          ]

          fileLink.href = fileURL;
          fileLink.setAttribute('download', `test.jpg`);
          document.body.appendChild(fileLink);

          fileLink.click();
        }
      }, 1000)

    }
  }, [downloadStream]);
  useEffect(() => {
    if (!scroll) return
    setLayer2Y(scroll.top / gScale);

  }, [scroll, gScale]);

  const getHeightByPeriod = (period: number, count: number) => {
    let rate = 60
    if (count >= 1500) {
      rate = 3
      setEdgeFontSize(8)
    } else if (100 < count && count < 1500) {
      rate = 10
      setEdgeFontSize(12)
    } else if (count < 100) {
      rate = 20
      setEdgeFontSize(12)
    }

    if (period === 0) {
      return 0 + 60
    }

    return Math.floor(Math.pow(period * 1000 * 1000, 1 / 7) * 100) / 100 * rate
  };
  useEffect(() => {
    if (summaries.length === 0) return
    let infoMaxLength = Math.sqrt(Math.max(...summaries.map(x => x.info.length))) * 30;
    setItemSpacing(infoMaxLength)
    let unique = Array.from(new Set(summaries.map(x => [x.source, x.destination]).flat()))
    const list: ItemGraph[] = unique.map((x, i) => {
      const itemWidth = x.length > 15 ? x.length * 7 : 100;
      return {
        name: x,
        x: 0,
        y: 0,
        width: itemWidth,
        height: itemHeight
      }
    })
    list.reduce((prev, curr) => {
      curr.x = prev.x + prev.width + infoMaxLength;
      curr.y = prev.y;
      return curr;
    });
    const layerWidth = list[list.length - 1].x + list[list.length - 1].width + infoMaxLength;
    const lines: ItemGraph[][] = summaries.map((s, i) => {
      let h = getHeightByPeriod(s.period, summaries.length);
      return list.map(x => {
        const itemWidth = x.name.length > 15 ? x.name.length * 7 : 100;
        return {
          name: x.name,
          x: 0,
          y: 0,
          width: itemWidth,
          height: h
        }
      })
    })
    lines.forEach(x => {
      x.reduce((prev, curr) => {
        curr.x = prev.x + prev.width + infoMaxLength;
        curr.y = prev.y;
        return curr;
      });
    });
    lines.reduce((prev, curr) => {
      curr.forEach(x => x.y = prev[0].y + prev[0].height);
      return curr
    });
    lines.forEach(x => {
      x.forEach(y => {
        y.x = y.x + y.width / 2
      })
    })
    const layerHeight = lines.map(x => x[0].height).reduce((x, y) => x + y) + itemHeight;
    setLayerSize({width: layerWidth, height: layerHeight});
    const arrows: EdgeProps[] = summaries.map((x, i) => {
      let startNode = lines[i].find(y => y.name === x.source)!;
      let startIndex = lines[i].findIndex(y => y.name === x.source);
      startNode = {...startNode, y: startNode.y + startNode.height / 2};
      let endNode = lines[i].find(y => y.name === x.destination)!;
      let endIndex = lines[i].findIndex(y => y.name === x.destination);
      endNode = {...endNode, y: endNode.y + endNode.height / 2};
      return {
        fontSize: 0,
        startNode: startNode!,
        endNode: endNode!,
        text1: x.info,
        arrow: startIndex < endIndex ? ArrowEnum.right : ArrowEnum.left,
        index: i,
        period: x.period,
        isHigh: false,
        onClick: (i) => {
          onClick(i)
        }
      }
    })
    setItemGraphs(list)
    setLineGraphs(lines)
    setEdges(arrows)

  }, [summaries]);
  useMount(() => {
    if (!pRef.current) return
    pRef.current?.addEventListener('wheel', (e) => {
      if (e.altKey) {
        e.preventDefault();
        const delta = e.deltaY;
        if (delta < 0) {
          scale = scale * 1.2
        } else {
          scale = scale / 1.2
        }
        setGScale(scale)
      }
    })
  })

  return (
    summaries.length === 0 ? null :
      <div
        onContextMenu={e => e.preventDefault()} // 禁止右键菜单
        ref={pRef} style={{width: pos1.x, height: "100%", overflow: 'auto'}}>
        <Stage
          scaleY={gScale}
          scaleX={gScale}
          width={layerSize.width * gScale}
          height={layerSize.height * gScale}
          ref={stageRef}
        >
          <Layer>
            {/*添加背景方形*/}
            <Rect x={0} y={0} width={layerSize.width * gScale} height={layerSize.height * gScale} fill="white"/>

            {
              lineGraphs.map((x, i) => {
                return x.map((y, j) => {
                  return <Line key={i + "," + j} x={y.x} y={y.y} stroke={'gray'} strokeWidth={1}
                               points={[0, 0, 0, y.height]}/>;
                })
              })
            }
            {
              edges.map((x, i) => {
                return <Edge key={i} {...x} fontSize={edgeFontSize}/>
              })
            }
            <Group y={layer2Y}>
              {itemGraphs.map((x, i) => {
                return [
                  <Rect
                    key={i + "rect2"}
                    strokeWidth={1}
                    fill={'white'}
                    width={x.width + itemSpacing}
                    height={x.height}
                    x={x.x}/>,
                  <Rect
                    key={i}
                    strokeWidth={1}
                    stroke={'black'}
                    width={x.width}
                    height={x.height}
                    x={x.x}
                  />,
                  <Text
                    key={i + "dudu"}
                    text={x.name}
                    fontSize={itemHeight - 2}
                    width={x.width}
                    height={itemHeight}
                    x={x.x}
                    align={'center'}
                    verticalAlign={'middle'}/>,
                ];
              })
              }
            </Group>

          </Layer>
        </Stage>
      </div>
  )
};

export default DrawScroll;
